package com.bestcem.xm.qdes.handler.export;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.qdes.enums.QuestionCustomTypeEnum;
import com.bestcem.xm.qdes.enums.QuestionTypeEnum;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import static com.bestcem.xm.qdes.enums.QuestionCustomTypeEnum.QUESTION_CUSTOM_TYPE_MATRIX_MULTIPLE_CLASSIFY;

public interface BaseTypeHandler {
    List<Object> getItems(JSONObject questionDict, JSONObject qgidDict, List<JSONObject> relatedRefs);

    String getType();

    default List<Object> getItems4MatrixSingle(JSONObject questionDict, JSONObject qgidDict, List<JSONObject> relatedRefs) {
        // 矩阵单选题
        List<Object> items = new ArrayList<>();
        String qcid = questionDict.getString("cid");
        String qtitle = questionDict.getString("title");
        String qtype = questionDict.getString("qtype");
        String customQtype = questionDict.getString("custom_qtype");

        int dispSelect = (int) questionDict.getOrDefault("dispSelect", 0);  // dispSelect:0 选项设置; 1 代码设置
        boolean codeSelect = (boolean) questionDict.getOrDefault("codeSelect", true); // true: 显示代码/false: 抹灰代码

        int jumpSelect = (int) questionDict.getOrDefault("jumpSelect", 0);  // jumpSelect:0 选项设置; 1 代码设

        String dispCode = (String) questionDict.getOrDefault("disp_code", "");  // 显示代码
        String jumpCode = (String) questionDict.getOrDefault("jump_code", "");  // 跳转代码
        String autoCode = (String) questionDict.getOrDefault("auto_code", "");  // 自动勾选代码

        boolean swap = (Boolean) questionDict.getOrDefault("swap", false); // 行列互换

        boolean required = questionDict.getBoolean("required");  // 必答
        String typeStr = QuestionTypeEnum.valueOf("QUESTION_TYPE_" + qtype.toUpperCase()).getDesc();

        boolean isClassify = QUESTION_CUSTOM_TYPE_MATRIX_MULTIPLE_CLASSIFY.getValue().equals(customQtype); // 是否为分类题
        boolean isMatrixBlank = "matrix_blank".equals(qtype);  // 是否为矩阵填空题

        List<String> item0 = new ArrayList<>();
        item0.add(qcid + "[" + typeStr + "]");
        item0.add(qtitle);

        List<String> qAttr = new ArrayList<>();
        qAttr.add(required ? "必答" : "非必答");
        if (swap) {
            qAttr.add("行列互换");
        }
        String iconstr = questionDict.getString("icon");
        if (StringUtils.isNotEmpty(iconstr)) {
            qAttr.add(String.format("图标#%s", iconstr));
        }

        if (dispSelect == 1 && codeSelect) {
            qAttr.add("显示代码");
        } else if (dispSelect == 1 && !codeSelect) {
            qAttr.add("抹灰代码");
        } else {
            qAttr.add("");
        }

        // 题目属性
        List<String> allAttr = new ArrayList<>();
        qAttr.forEach(at -> {
            allAttr.add("[" + at + "]");
        });
        item0.add(String.join("", allAttr));
        // 显示代码，跳转代码，自动勾选代码
        item0.add(dispSelect == 1 ? dispCode : "");
        item0.add(jumpSelect == 1 ? jumpCode : "");
        item0.add(autoCode);
        items.add(item0);

        // 处理选项
        List<Object> optionRows = new ArrayList<>();
        String optionsRandom = questionDict.getString("options_random"); // 选项顺序: True, "sort", "reverse"

        JSONArray optionItems = Optional.ofNullable(questionDict.getJSONArray("items")).orElse(new JSONArray());
        if (!optionItems.isEmpty() || CollectionUtils.isNotEmpty(relatedRefs)) {
            List<String> optionCommAttr = new ArrayList<>();  // 选项属性
            optionCommAttr.add("顺序#" + ("True".equals(optionsRandom) ? "随机" : ("sort".equals(optionsRandom) ? "循环"
                    : ("reverse".equals(optionsRandom) ? "倒序" : "默认"))));

            // 处理选项关联
            if (CollectionUtils.isNotEmpty(relatedRefs)) {
                List<String> relatedTmps = new ArrayList<>();
                for (JSONObject related : relatedRefs) {
                    String sourceGid = related.getString("sourceGid");
                    String mode = related.getString("mode");
                    JSONObject question = qgidDict.getJSONObject(sourceGid);

                    List<String> tmps = new ArrayList<>();
                    tmps.add("关联");
                    tmps.add(question.getString("cid"));
                    tmps.add("unselect".equals(mode) ? "未选中项" : "选中项");
                    relatedTmps.add(String.join("#", tmps));
                }
                optionCommAttr.addAll(relatedTmps);
            }
            List<String> tmpList = new ArrayList<>();
            tmpList.add("选项");
            tmpList.add("");
            List<String> comAttr = new ArrayList<>();
            optionCommAttr.forEach(at -> {
                comAttr.add("[" + at + "]");
            });
            tmpList.add(String.join("", comAttr));
            optionRows.add(tmpList);

            for (Object oneItem : optionItems) {
                JSONObject optionDict = (JSONObject) oneItem;
                List<String> rowAttr = new ArrayList<>();

                boolean isOpen = optionDict.getBoolean("is_open");

                String dispCode1 = (String) optionDict.getOrDefault("disp_code", "");  // 显示代码
                String plasterCode1 = (String) optionDict.getOrDefault("plaster_code", "");  // 抹灰代码
                autoCode = (String) optionDict.getOrDefault("auto_code", "");  // 自动勾选代码
                boolean forbidRelated = (Boolean) optionDict.getOrDefault("forbidRelated", false); // 禁止选项关联
                boolean exclusive = (Boolean) optionDict.getOrDefault("exclusive", false); // 选项排他
                boolean fixed = (Boolean) optionDict.getOrDefault("fixed", false); // 选项固定

                if (forbidRelated) {
                    rowAttr.add("禁止选项关联");
                }
                if (exclusive) {
                    rowAttr.add("选项排他");
                }
                if (fixed) {
                    rowAttr.add("选项固定");
                }
                if (isOpen) {
                    JSONObject openAttrs = (JSONObject) optionDict.getOrDefault("open_attrs", new JSONObject());
                    List<String> optionOpenAttrs = optionOpenParse(openAttrs);
                    rowAttr.add(String.join("#", optionOpenAttrs));
                }

                if (isMatrixBlank) {
                    JSONObject openAttrs = (JSONObject) optionDict.getOrDefault("open_attrs", new JSONObject());
                    List<String> optionOpenAttrs = optionOpenParse(openAttrs);
                    rowAttr.add(String.join("#", optionOpenAttrs.subList(1, optionOpenAttrs.size())));
                }

                List<String> opAttr = new ArrayList<>();
                rowAttr.forEach(at -> {
                    opAttr.add("[" + at + "]");
                });
                String optionAttrstr = String.join("", opAttr);

                List<String> tList = new ArrayList<>();
                tList.add(optionDict.getString("oid"));
                tList.add(optionDict.getString("title"));
                tList.add(optionAttrstr);
                if (dispSelect == 1 && codeSelect) {
                    tList.add(dispCode1);
                } else if (dispSelect == 1 && !codeSelect) {
                    tList.add(plasterCode1);
                } else {
                    tList.add("");
                }
                tList.add("");
                tList.add(autoCode);
                optionRows.add(tList);
            }
        }

        List<Object> matrixRows = new ArrayList<>();
        // 处理矩阵行
        String rowsRandom = questionDict.getString("rows_random"); // 矩阵行顺序：False, True, "sort", "reverse"
        JSONArray rowsItems = (JSONArray) questionDict.getOrDefault("rows_items", new JSONArray());  // 矩阵行
        String uniqueStr = questionDict.getString("unique"); //唯一性
        Boolean unique = !StringUtils.isEmpty(uniqueStr) && (!"none".equals(uniqueStr) && Boolean.parseBoolean(uniqueStr));
        if (CollectionUtils.isNotEmpty(rowsItems)) {
            List<String> rowCommAttr = new ArrayList<>();
            rowCommAttr.add("顺序#" + ("True".equals(rowsRandom) ? "随机" : ("sort".equals(rowsRandom) ? "循环"
                    : ("reverse".equals(rowsRandom) ? "倒序" : "默认"))));

            boolean showMatrixRWord = (Boolean) questionDict.getOrDefault("showMatrixRWord", false);  // 矩阵行右极文字
            if (showMatrixRWord) {
                rowCommAttr.add("右极文字");
            }
            if (unique) {
                rowCommAttr.add("答案唯一");
            }

            List<String> roAttr = new ArrayList<>();
            rowCommAttr.forEach(at -> {
                roAttr.add("[" + at + "]");
            });
            String rowAttrstr = String.join("", roAttr);
            matrixRows.add(Arrays.asList("矩阵行", "", rowAttrstr));  // 选项标识行

            for (Object oneItem : rowsItems) {
                JSONObject rowDict = (JSONObject) oneItem;
                List<String> rowAttr = new ArrayList<>();

                boolean isOpen = rowDict.getBoolean("is_open");

                String dispCode1 = (String) rowDict.getOrDefault("disp_code", "");  // 显示代码
                String plasterCode1 = (String) rowDict.getOrDefault("plaster_code", "");  // 抹灰代码
                autoCode = (String) rowDict.getOrDefault("auto_code", "");  // 自动勾选代码
                String rightWord = rowDict.getString("rightWord"); // 右极文字
                required = (Boolean) rowDict.getOrDefault("required", false); // 必答
                boolean fixed = (Boolean) rowDict.getOrDefault("fixed", false); // 选项固定

                rowAttr.add(required ? "必答" : "非必答");
                if (showMatrixRWord && StringUtils.isNotEmpty(rightWord)) {
                    rowAttr.add(String.format("右极文字#%s", rightWord));
                }
                if (fixed) {
                    rowAttr.add("固定");
                }
                if (isOpen) {
                    JSONObject openAttrs = (JSONObject) rowDict.getOrDefault("open_attrs", new JSONObject());
                    List<String> optionOpenAttrs = optionOpenParse(openAttrs);
                    rowAttr.add(String.join("#", optionOpenAttrs));
                }

                List<String> opAttr = new ArrayList<>();
                rowAttr.forEach(at -> {
                    opAttr.add("[" + at + "]");
                });
                String optionAttrstr = String.join("", opAttr);

                List<String> tList = new ArrayList<>();
                tList.add(rowDict.getString("oid"));
                tList.add(rowDict.getString("title"));
                tList.add(optionAttrstr);
                if (dispSelect == 1 && codeSelect) {
                    tList.add(dispCode1);
                } else if (dispSelect == 1 && !codeSelect) {
                    tList.add(plasterCode1);
                } else {
                    tList.add("");
                }
                tList.add("");
                tList.add(autoCode);
                matrixRows.add(tList);
            }
        }

        if (!isClassify) {
            // 处理选项
            items.addAll(optionRows);

            // 处理选项分组
            boolean optionsGroupEffect = (Boolean) questionDict.getOrDefault("optionsGroupEffect", false); // 是否启用 选项分组
            boolean showOptionsGroupTitle = (Boolean) questionDict.getOrDefault("showOptionsGroupTitle", false); // 选项分组：显示组名
            JSONArray optionGroupList = (JSONArray) questionDict.getOrDefault("option_group_list", new JSONArray()); // 选项分组列表
            String optionsGroupRandom = questionDict.getString("options_group_random"); // 选项组间顺序：默认，随机，循环，倒序

            if (optionsGroupEffect) {
                List<String> optionGroupAttrs = new ArrayList<>();

                optionGroupAttrs.add("顺序#" + ("True".equals(optionsGroupRandom) ? "随机" : ("sort".equals(optionsGroupRandom) ? "循环"
                        : ("reverse".equals(optionsGroupRandom) ? "倒序" : "默认"))));
                optionGroupAttrs.add(showOptionsGroupTitle ? "显示组名" : "不显示组名");

                // 选项分组标识行
                List<String> tList = new ArrayList<>();
                tList.add("选项分组");
                tList.add("");
                List<String> gAttr = new ArrayList<>();
                optionGroupAttrs.forEach(at -> {
                    gAttr.add("[" + at + "]");
                });
                tList.add(String.join("", gAttr));
                items.add(tList);

                for (Object optionG : optionGroupList) {
                    JSONObject optionGroup = (JSONObject) optionG;
                    String optionGroupTitle = optionGroup.getString("title");
                    boolean optionGroupFixed = optionGroup.getBoolean("fixed");
                    JSONArray optionGroupItems = (JSONArray) optionGroup.getOrDefault("items", new JSONArray());
                    String optionGroupDispCode = (String) optionGroup.getOrDefault("disp_code", "");
                    List<String> ogQcids = new ArrayList<>();
                    optionGroupItems.forEach(omp -> {
                        JSONObject otmp = (JSONObject) omp;
                        ogQcids.add(otmp.getString("oid"));
                    });

                    List<String> tmList = new ArrayList<>();
                    tmList.add(optionGroupTitle);
                    tmList.add(String.join(",", ogQcids));
                    tmList.add(optionGroupFixed ? "[固定]" : "");
                    tmList.add(dispSelect == 1 ? optionGroupDispCode : "");
                    items.add(tmList);
                }
            }

            // 选项绑定
            if ("True".equals(optionsRandom)) {
                boolean optionsBindEffect = questionDict.getBoolean("optionsBindEffect");  // 是否启用 选项绑定 选项顺序：随机
                List<JSONObject> optionBindList = questionDict.getObject("option_bind_list", List.class);  // 选项绑定列表
                if (optionsBindEffect && CollectionUtils.isNotEmpty(optionBindList)) {
                    items.add(Arrays.asList("选项绑定", "", "", "", "", ""));  // 选项绑定 标识行
                    for (JSONObject optionBind : optionBindList) {
                        String title1 = optionBind.getString("title");
                        JSONArray items1 = (JSONArray) optionBind.getOrDefault("items", new JSONArray());
                        List<String> ogQcids = new ArrayList<>();
                        items1.forEach(otmp -> {
                            ogQcids.add(((JSONObject) otmp).getString("oid"));
                        });
                        items.add(Arrays.asList(title1, String.join(",", ogQcids), "", "", "", ""));
                    }
                }
            }
            // 处理矩阵行
            items.addAll(matrixRows);
            // 处理矩阵行分组
            boolean rowsGroupEffect = (Boolean) questionDict.getOrDefault("rowsGroupEffect", false); //是否启用：矩阵行分组
            boolean showRowsGroupTitle = (Boolean) questionDict.getOrDefault("showRowsGroupTitle", false); // 矩阵行分组：显示组名
            JSONArray rowGroupList = questionDict.getJSONArray("row_group_list"); // 矩阵行分组
            String rowsGroupRandom = questionDict.getString("rows_group_random"); // 矩阵行组间 顺序: False, True, "sort", "reverse"

            if (rowsGroupEffect) {
                List<String> rowGroupAttrs = new ArrayList<>();
                rowGroupAttrs.add("顺序#" + ("True".equals(rowsGroupRandom) ? "随机" : ("sort".equals(rowsGroupRandom) ? "循环"
                        : ("reverse".equals(rowsGroupRandom) ? "倒序" : "默认"))));
                rowGroupAttrs.add(showRowsGroupTitle ? "显示组名" : "不显示组名");
                // 选项分组标识行
                List<String> tList = new ArrayList<>();
                tList.add("矩阵行分组");
                tList.add("");
                List<String> gAttr = new ArrayList<>();
                rowGroupAttrs.forEach(at -> {
                    gAttr.add("[" + at + "]");
                });
                tList.add(String.join("", gAttr));
                items.add(tList);

                for (Object optionG : rowGroupList) {
                    JSONObject rowGroup = (JSONObject) optionG;
                    String rowGroupTitle = rowGroup.getString("title");
                    boolean rowGroupFixed = rowGroup.getBoolean("fixed");
                    JSONArray rowGroupItems = (JSONArray) rowGroup.getOrDefault("items", new JSONArray());
                    String rowGroupDispCode = (String) rowGroup.getOrDefault("disp_code", "");
                    String rowGroupPlasterCode = (String) rowGroup.getOrDefault("plaster_code", "");
                    List<String> ogQcids = new ArrayList<>();
                    rowGroupItems.forEach(omp -> {
                        JSONObject otmp = (JSONObject) omp;
                        ogQcids.add(otmp.getString("oid"));
                    });

                    List<String> tmList = new ArrayList<>();
                    tmList.add(rowGroupTitle);
                    tmList.add(String.join(",", ogQcids));
                    tmList.add(rowGroupFixed ? "[固定]" : "");
                    if (dispSelect == 1 && codeSelect) {
                        tmList.add(rowGroupDispCode);
                    } else if (dispSelect == 1 && !codeSelect) {
                        tmList.add(rowGroupPlasterCode);
                    } else {
                        tmList.add("");
                    }
                    items.add(tmList);
                }
            }
            // 处理矩阵行绑定
            if ("True".equals(rowsRandom)) {
                boolean rowsBindEffect = questionDict.getBoolean("rowsBindEffect");  // 矩阵行绑定
                List<JSONObject> rowBindList = questionDict.getObject("row_bind_list", List.class); // 矩阵行绑定
                if (rowsBindEffect && CollectionUtils.isNotEmpty(rowBindList)) {
                    items.add(Arrays.asList("矩阵行绑定", "", "", "", "", ""));  // 矩阵行绑定 标识行
                    for (JSONObject rowBind : rowBindList) {
                        String title1 = rowBind.getString("title");
                        JSONArray items1 = (JSONArray) rowBind.getOrDefault("items", new JSONArray());
                        List<String> ogQcids = new ArrayList<>();
                        items1.forEach(omp -> {
                            JSONObject otmp = (JSONObject) omp;
                            ogQcids.add(otmp.getString("oid"));
                        });
                        items.add(Arrays.asList(title1, String.join(",", ogQcids), "", "", "", ""));
                    }
                }
            }
        } else {
            // 分类题，矩阵行优先，标志：分类
            // 处理矩阵行
            List<String> matrixRow0 = castList(matrixRows.get(0), String.class);
            matrixRow0.set(0, "分类");
            matrixRows.set(0, matrixRow0);
            items.addAll(matrixRows);
            // 处理选项
            items.addAll(optionRows);
        }
        return items;
    }

    default List<Object> getItems4Single(JSONObject questionDict, JSONObject qgidDict, List<JSONObject> relatedRefs) {
        /**
         * 处理单选题
         *     :param questionDict:
         *     :param related_refs:
         *         关联结构: [{
         *                 "sourceGid": 65,
         *                 "targetGid": 83,
         *                 "type": "O",
         *                 "mode": "unselect"
         *             }, {
         *                 "sourceGid": 71,
         *                 "targetGid": 83,
         *                 "type": "O",
         *                 "mode": "select"
         *             }
         *         ]
         */
        List<Object> items = new ArrayList<>();
        String qgid = questionDict.getString("gid");
        String qcid = questionDict.getString("cid");
        String qtitle = questionDict.getString("title");
        String qtype = questionDict.getString("qtype");
        String customQtype = questionDict.getString("custom_qtype");

        int dispSelect = (int) questionDict.getOrDefault("dispSelect", 0);  // dispSelect:0 选项设置; 1 代码设置
        boolean codeSelect = (boolean) questionDict.getOrDefault("codeSelect", true); // true: 显示代码/false: 抹灰代码
        int jumpSelect = (int) questionDict.getOrDefault("jumpSelect", 0);  // jumpSelect:0 选项设置; 1 代码设
        String dispCode = (String) questionDict.getOrDefault("disp_code", "");  // 显示代码
        String jumpCode = (String) questionDict.getOrDefault("jump_code", "");  // 跳转代码
        String autoCode = (String) questionDict.getOrDefault("auto_code", "");  // 自动勾选代码

        boolean voteSetting = (Boolean) questionDict.getOrDefault("vote_setting", false);  // 答题后展示投票结果: true/false
        String answerStyle = (String) questionDict.getOrDefault("answerStyle", "custom");  // 下拉单选题: select
        boolean required = (Boolean) questionDict.getOrDefault("required", false);  // 必答
        String typeStr = QuestionTypeEnum.valueOf("QUESTION_TYPE_" + qtype.toUpperCase()).getDesc();

        if ("image_select".equals(customQtype)) {
            return items;
        }
        if (StringUtils.isNotEmpty(customQtype)) {
            try {
                QuestionCustomTypeEnum customQtypeDesc = QuestionCustomTypeEnum.valueOf("QUESTION_CUSTOM_TYPE_" + customQtype.toUpperCase());
                if (customQtypeDesc != null && StringUtils.isNotEmpty(customQtypeDesc.getDesc())) {
                    typeStr = customQtypeDesc.getDesc();
                }
            } catch (IllegalArgumentException exp) {
                System.err.println("No found QuestionCustomTypeEnum");
            }
        }

        List<String> item0 = new ArrayList<>();
        item0.add(qcid + "[" + typeStr + "]");
        item0.add(qtitle);

        List<String> qAttr = new ArrayList<>();
        qAttr.add(required ? "必答" : "非必答");
        if (voteSetting && ("single".equals(customQtype) || "image_select".equals(customQtype))) {
            qAttr.add("投票统计");
        }
        if ("select".equals(answerStyle)) {
            qAttr.add("下拉单选");
        }

        if (dispSelect == 1 && codeSelect) {
            qAttr.add("显示代码");
        } else if (dispSelect == 1 && !codeSelect) {
            qAttr.add("抹灰代码");
        } else {
            qAttr.add("");
        }
        // 题目属性
        List<String> allAttr = new ArrayList<>();
        qAttr.forEach(at -> {
            allAttr.add("[" + at + "]");
        });
        item0.add(String.join("", allAttr));
        // 显示代码，跳转代码，自动勾选代码
        item0.add(dispSelect == 1 ? dispCode : "");
        item0.add(jumpSelect == 1 ? jumpCode : "");
        item0.add(autoCode);
        items.add(item0);

        // 处理选项
        String optionsRandom = questionDict.getString("options_random"); // 选项顺序: True, "sort", "reverse"
        String optionAlign = questionDict.getString("align"); // 选项排列: "horizontal",  "vertical"
        String columnValue = questionDict.getString("column_value"); // 横排 每行列数

        JSONArray optionItems = Optional.ofNullable(questionDict.getJSONArray("items")).orElse(new JSONArray());
        if (!optionItems.isEmpty() || CollectionUtils.isNotEmpty(relatedRefs)) {
            List<String> optionCommAttr = new ArrayList<>();  // 选项属性
            optionCommAttr.add("顺序#" + ("True".equals(optionsRandom) ? "随机" : ("sort".equals(optionsRandom) ? "循环"
                    : ("reverse".equals(optionsRandom) ? "倒序" : "默认"))));
            optionCommAttr.add("排列#" + ("横排#每行" + ("horizontal".equals(optionAlign)
                    ? (StringUtils.isNotEmpty(columnValue) ? columnValue : "竖排") : "竖排")) + "列");

            // 处理选项关联
            if (CollectionUtils.isNotEmpty(relatedRefs)) {
                List<String> relatedTmps = new ArrayList<>();
                for (JSONObject related : relatedRefs) {
                    String sourceGid = related.getString("sourceGid");
                    String mode = related.getString("mode");
                    JSONObject question = qgidDict.getJSONObject(sourceGid);

                    List<String> tmps = new ArrayList<>();
                    tmps.add("关联");
                    tmps.add(question.getString("cid"));
                    tmps.add("unselect".equals(mode) ? "未选中项" : "选中项");
                    relatedTmps.add(String.join("#", tmps));
                }
                optionCommAttr.addAll(relatedTmps);
            }
            List<String> tmpList = new ArrayList<>();
            tmpList.add("选项");
            tmpList.add("");
            List<String> comAttr = new ArrayList<>();
            optionCommAttr.forEach(at -> {
                comAttr.add("[" + at + "]");
            });
            tmpList.add(String.join("", comAttr));
            items.add(tmpList);
            String aa = "";

            for (Object oneItem : optionItems) {
                JSONObject optionDict = (JSONObject) oneItem;
                List<String> optionAttr = new ArrayList<>();
                boolean isOpen = (Boolean) optionDict.getOrDefault("is_open", false);

                String dispCode1 = (String) optionDict.getOrDefault("disp_code", "");  // 显示代码
                String plasterCode1 = (String) optionDict.getOrDefault("plaster_code", "");  // 抹灰代码
                autoCode = (String) optionDict.getOrDefault("auto_code", "");  // 自动勾选代码
                boolean forbidRelated = (Boolean) optionDict.getOrDefault("forbidRelated", false); // 禁止选项关联
                boolean exclusive = (Boolean) optionDict.getOrDefault("exclusive", false); // 选项排他
                boolean fixed = (Boolean) optionDict.getOrDefault("fixed", false); // 选项固定

                if (forbidRelated) {
                    optionAttr.add("禁止选项关联");
                }
                if (exclusive) {
                    optionAttr.add("选项排他");
                }
                if (fixed) {
                    optionAttr.add("固定");
                }
                if (isOpen) {
                    JSONObject openAttrs = (JSONObject) optionDict.getOrDefault("open_attrs", new JSONObject());
                    List<String> optionOpenAttrs = optionOpenParse(openAttrs);
                    optionAttr.add(String.join("#", optionOpenAttrs));
                }

                List<String> opAttr = new ArrayList<>();
                optionAttr.forEach(at -> {
                    opAttr.add("[" + at + "]");
                });
                String optionAttrstr = String.join("", opAttr);

                List<String> tList = new ArrayList<>();
                tList.add(optionDict.getString("oid"));
                tList.add(optionDict.getString("title"));
                tList.add(optionAttrstr);
                if (dispSelect == 1 && codeSelect) {
                    tList.add(dispCode1);
                } else if (dispSelect == 1 && !codeSelect) {
                    tList.add(plasterCode1);
                } else {
                    tList.add("");
                }
                tList.add("");
                tList.add(autoCode);
                items.add(tList);
            }
        }

        // 处理选项分组
        boolean optionsGroupEffect = (Boolean) questionDict.getOrDefault("optionsGroupEffect", false); // 是否启用 选项分组
        boolean showOptionsGroupTitle = (Boolean) questionDict.getOrDefault("showOptionsGroupTitle", false); // 选项分组：显示组名
        JSONArray optionGroupList = (JSONArray) questionDict.getOrDefault("option_group_list", new JSONArray()); // 选项分组列表
        String optionsGroupRandom = questionDict.getString("options_group_random"); // 选项组间顺序：默认，随机，循环，倒序
        String groupAlign = questionDict.getString("group_align"); // 选项分组排列：横、竖
        String groupColumnValue = questionDict.getString("group_column_value"); // 分组横排：每行列数

        if (optionsGroupEffect) {
            List<String> optionGroupAttrs = new ArrayList<>();

            optionGroupAttrs.add("顺序#" + ("True".equals(optionsGroupRandom) ? "随机" : ("sort".equals(optionsGroupRandom) ? "循环"
                    : ("reverse".equals(optionsGroupRandom) ? "倒序" : "默认"))));
            optionGroupAttrs.add("排列#" + ("横排#每行" + ("horizontal".equals(groupAlign)
                    ? (StringUtils.isNotEmpty(groupColumnValue) ? groupColumnValue : "竖排") : "竖排")) + "列");
            optionGroupAttrs.add(showOptionsGroupTitle ? "显示组名" : "不显示组名");

            // 选项分组标识行
            List<String> tList = new ArrayList<>();
            tList.add("选项分组");
            tList.add("");
            List<String> gAttr = new ArrayList<>();
            optionGroupAttrs.forEach(at -> {
                gAttr.add("[" + at + "]");
            });
            tList.add(String.join("", gAttr));
            items.add(tList);

            for (Object optionG : optionGroupList) {
                JSONObject optionGroup = (JSONObject) optionG;
                String optionGroupTitle = optionGroup.getString("title");
                boolean optionGroupFixed = optionGroup.getBoolean("fixed");
                JSONArray optionGroupItems = (JSONArray) optionGroup.getOrDefault("items", new JSONArray());
                String optionGroupDispCode = (String) optionGroup.getOrDefault("disp_code", "");
                List<String> ogQcids = new ArrayList<>();
                optionGroupItems.forEach(omp -> {
                    JSONObject otmp = (JSONObject) omp;
                    ogQcids.add(otmp.getString("oid"));
                });

                List<String> tmList = new ArrayList<>();
                tmList.add(optionGroupTitle);
                tmList.add(String.join(",", ogQcids));
                tmList.add(optionGroupFixed ? "[固定]" : "");
                tmList.add(dispSelect == 1 ? optionGroupDispCode : "");
                items.add(tmList);
            }
        }

        // 选项绑定
        if ("True".equals(optionsRandom)) {
            boolean optionsBindEffect = questionDict.getBoolean("optionsBindEffect");  // 是否启用 选项绑定 选项顺序：随机
            List<JSONObject> optionBindList = questionDict.getObject("option_bind_list", List.class);  // 选项绑定列表
            if (optionsBindEffect && CollectionUtils.isNotEmpty(optionBindList)) {
                items.add(Arrays.asList("选项绑定", "", "", "", "", ""));  // 选项绑定 标识行
                for (JSONObject optionBind : optionBindList) {
                    String title1 = optionBind.getString("title");
                    JSONArray items1 = (JSONArray) optionBind.getOrDefault("items", new JSONArray());
                    List<String> ogQcids = new ArrayList<>();
                    items1.forEach(otmp -> {
                        ogQcids.add(((JSONObject) otmp).getString("oid"));
                    });
                    items.add(Arrays.asList(title1, String.join(",", ogQcids), "", "", "", ""));
                }
            }
        }
        return items;
    }

    default List<Object> getItems4Timedelta(JSONObject questionDict, JSONObject qgidDict, List<JSONObject> relatedRefs) {
        // 时间题
        List<Object> items = new ArrayList<>();

        String qcid = questionDict.getString("cid");
        String qtitle = questionDict.getString("title");
        String qtype = questionDict.getString("qtype");

        int dispSelect = (int) questionDict.getOrDefault("dispSelect", 0);  // dispSelect:0 选项设置; 1 代码设置
        boolean codeSelect = (boolean) questionDict.getOrDefault("codeSelect", true); // true: 显示代码/false: 抹灰代码

        int jumpSelect = (int) questionDict.getOrDefault("jumpSelect", 0);  // jumpSelect:0 选项设置; 1 代码设
        String dispCode = (String) questionDict.getOrDefault("disp_code", "");  // 显示代码
        String jumpCode = (String) questionDict.getOrDefault("jump_code", "");  // 跳转代码
        String autoCode = (String) questionDict.getOrDefault("auto_code", "");  // 自动勾选代码

        boolean required = questionDict.getBoolean("required");  // 必答

        String typeStr = QuestionTypeEnum.valueOf("QUESTION_TYPE_" + qtype.toUpperCase()).getDesc();

        List<String> item0 = new ArrayList<>();
        item0.add(qcid + "[" + typeStr + "]");
        item0.add(qtitle);

        List<String> qAttr = new ArrayList<>();
        qAttr.add(required ? "必答" : "非必答");

        if (dispSelect == 1 && codeSelect) {
            qAttr.add("显示代码");
        } else if (dispSelect == 1 && !codeSelect) {
            qAttr.add("抹灰代码");
        } else {
            qAttr.add("");
        }
        // 题目属性
        List<String> allAttr = new ArrayList<>();
        qAttr.forEach(at -> {
            allAttr.add("[" + at + "]");
        });
        item0.add(String.join("", allAttr));
        // 显示代码，跳转代码，自动勾选代码
        item0.add(dispSelect == 1 ? dispCode : "");
        item0.add(jumpSelect == 1 ? jumpCode : "");
        item0.add(autoCode);
        items.add(item0);

        return items;
    }

    default String openContentLimitTrans(String openType) {
        // 开放框内容限制
        if ("0".equals(openType)) {
            return "不限";
        } else if ("int".equals(openType)) {
            return "整数";
        } else if ("number".equals(openType)) {
            return "小数";
        } else if ("lang_en".equals(openType)) {
            return "字母";
        } else if ("lang_ch".equals(openType)) {
            return "中文";
        } else if ("email".equals(openType)) {
            return "邮件";
        } else if ("date".equals(openType)) {
            return "日期";
        } else if ("mobile".equals(openType)) {
            return "手机号码";
        } else if ("tel".equals(openType)) {
            return "固话";
        } else if ("mobile_tel".equals(openType)) {
            return "手机/固话";
        } else if ("idCard".equals(openType)) {
            return "身份证号";
        } else {
            return null;
        }
    }

    default List<String> optionOpenParse(JSONObject openAttrs) {
        // 处理选项开发框属性
        List<String> optionOpenAttr = new ArrayList<>();
        boolean optionOpenRequired = openAttrs.getBoolean("required");
        String optionOpenType = openAttrs.getString("type");
        String uniqueStr = openAttrs.getString("unique"); //唯一性
        boolean optionOpenUnique = !StringUtils.isEmpty(uniqueStr) && (!"none".equals(uniqueStr) && Boolean.parseBoolean(uniqueStr));

        Object optionOpenRange = openAttrs.get("range");

        optionOpenAttr.add("开放");
        if (optionOpenRequired) {
            optionOpenAttr.add("必填");
        }
        if (optionOpenUnique) {
            optionOpenAttr.add("唯一");
        }

        String openLimits = openContentLimitTrans(optionOpenType);
        if (openLimits != null) {
            optionOpenAttr.add(openLimits);
        }

        String rangeTxt = "";
        if (optionOpenRange instanceof List) {
            List<String> listR = castList(optionOpenRange, String.class);
            rangeTxt = String.join("-", listR);
        }

        if ("date".equals(optionOpenType) && optionOpenRange != null) {
            String optionOpenR = optionOpenRange.toString();
            if ("yyyy".equals(optionOpenR)) {
                rangeTxt = "年";
            } else if ("yyyy-MM".equals(optionOpenR)) {
                rangeTxt = "年-月";
            } else if ("yyyy-MM-dd".equals(optionOpenR)) {
                rangeTxt = "年-月-日";
            }
        }
        if (StringUtils.isNotEmpty(rangeTxt)) {
            optionOpenAttr.add(rangeTxt);
        }
        return optionOpenAttr;
    }

    default <T> List<T> castList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<>();
        if (obj instanceof List<?>) {
            for (Object o : (List<?>) obj) {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }
}
